package org.mzx.shortLink.start.designpattern.Chain;

import cn.hutool.core.collection.CollectionUtil;
import org.mzx.shortLink.starter.base.ApplicationContextHolder;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mazhenxi
 * @date 2025/4/23
 */
public class AbstractChainContext<T> implements CommandLineRunner {
    private Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();

    //责任链的执行逻辑，取出责任链中的逻辑进行执行
    public void handler(String mark,T requestParam) {
        List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
        //从责任链上下文中取出我们需要的模块的责任链（List）
        if (CollectionUtil.isEmpty(abstractChainHandlers)) {
            throw new RuntimeException(String.format("[%s] 没有相关责任链的设置",mark));
        }
        //依次执行其handler方法
        abstractChainHandlers.forEach(each-> {
            each.handler(requestParam);
        });
    }



    @Override
    public void run(String... args) throws Exception {
        //在bean完全加载完并且springboot已经初始化完毕后，从spring容器中找到对应的责任链类，也就是实现了抽象责任链接口的类AbstractChainHandler
        Map<String, AbstractChainHandler> chainHandlerMap = ApplicationContextHolder.getBeansOfType(AbstractChainHandler.class);
        //这里获得了所有的责任链接口的Bean
        chainHandlerMap.forEach((beanName,bean)-> {
            //在这里给Bean分类，根据我们的mark区分不同模块或者业务的责任链
            List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark());
            //如果遍历的过程中，这个责任链中的某一环是第一次出现的，我们的责任链上下文中还没有呢，所以我们需要新创建一个list保存这个模块或业务的责任链
            //即每一个List<AbstractChainHandler>就是一个责任链
            if(CollectionUtil.isEmpty(abstractChainHandlers)) {
                abstractChainHandlers = new ArrayList<>();
            }
            //把我们遍历到的责任链Bean插入到对应的分组中去
            abstractChainHandlers.add(bean);
            //这里是给组内的责任链进行排序，根据Order接口的顺序，决定执行顺序
            List<AbstractChainHandler> acturalAbstactChainHandler = abstractChainHandlers.stream()
                    .sorted(Comparator.comparing(Ordered::getOrder))
                    .collect(Collectors.toList());
            abstractChainHandlerContainer.put(bean.mark(),acturalAbstactChainHandler);
        });
    }
}
